/*
 *   Copyright 2021 zzh
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

package com.aduib.boot.common.util;

import java.util.AbstractMap;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @description: MapUtils
 * @author: zzh
 * @date: 2021/10/29 13:46
 */
public class MapUtils extends ListUtils{

  /** 默认初始大小 */
  public static final int DEFAULT_INITIAL_CAPACITY = 16;
  /** 默认增长因子，当Map的size达到 容量*增长因子时，开始扩充Map */
  public static final float DEFAULT_LOAD_FACTOR = 0.75f;

  /**
   * Map是否为空
   *
   * @param map 集合
   * @return 是否为空
   */
  public static boolean isEmpty(Map<?, ?> map) {
    return null == map || map.isEmpty();
  }

  /**
   * Map是否为非空
   *
   * @param map 集合
   * @return 是否为非空
   */
  public static boolean isNotEmpty(Map<?, ?> map) {
    return null != map && false == map.isEmpty();
  }

  // -----------------------------------------------------------------------------------------------
  // new HashMap

  /**
   * 新建一个HashMap
   *
   * @param <K> Key类型
   * @param <V> Value类型
   * @return HashMap对象
   */
  public static <K, V> HashMap<K, V> newHashMap() {
    return new HashMap<>();
  }

  /**
   * 新建一个HashMap
   *
   * @param <K> Key类型
   * @param <V> Value类型
   * @param size 初始大小，由于默认负载因子0.75，传入的size会实际初始大小为size / 0.75 + 1
   * @param isOrder Map的Key是否有序，有序返回 {@link LinkedHashMap}，否则返回 {@link HashMap}
   * @return HashMap对象
   */
  public static <K, V> HashMap<K, V> newHashMap(int size, boolean isOrder) {
    int initialCapacity = (int) (size / DEFAULT_LOAD_FACTOR) + 1;
    return isOrder ? new LinkedHashMap<>(initialCapacity) : new HashMap<>(initialCapacity);
  }

  /**
   * 新建一个HashMap
   *
   * @param <K> Key类型
   * @param <V> Value类型
   * @param size 初始大小，由于默认负载因子0.75，传入的size会实际初始大小为size / 0.75 + 1
   * @return HashMap对象
   */
  public static <K, V> HashMap<K, V> newHashMap(int size) {
    return newHashMap(size, false);
  }

  /**
   * 新建一个HashMap
   *
   * @param <K> Key类型
   * @param <V> Value类型
   * @param isOrder Map的Key是否有序，有序返回 {@link LinkedHashMap}，否则返回 {@link HashMap}
   * @return HashMap对象
   */
  public static <K, V> HashMap<K, V> newHashMap(boolean isOrder) {
    return newHashMap(DEFAULT_INITIAL_CAPACITY, isOrder);
  }

  /**
   * 新建TreeMap，Key有序的Map
   *
   * @param <K> key的类型
   * @param <V> value的类型
   * @param comparator Key比较器
   * @return TreeMap
   */
  public static <K, V> TreeMap<K, V> newTreeMap(Comparator<? super K> comparator) {
    return new TreeMap<>(comparator);
  }

  /**
   * 新建TreeMap，Key有序的Map
   *
   * @param <K> key的类型
   * @param <V> value的类型
   * @param map Map
   * @param comparator Key比较器
   * @return TreeMap
   */
  public static <K, V> TreeMap<K, V> newTreeMap(Map<K, V> map, Comparator<? super K> comparator) {
    final TreeMap<K, V> treeMap = new TreeMap<>(comparator);
    if (false == isEmpty(map)) {
      treeMap.putAll(map);
    }
    return treeMap;
  }

  /**
   * 创建键不重复Map
   *
   * @param <K> key的类型
   * @param <V> value的类型
   * @param size 初始容量
   * @return {@link IdentityHashMap}
   */
  public static <K, V> Map<K, V> newIdentityMap(int size) {
    return new IdentityHashMap<>(size);
  }

  /**
   * 新建一个初始容量为{@link MapUtils#DEFAULT_INITIAL_CAPACITY} 的ConcurrentHashMap
   *
   * @param <K> key的类型
   * @param <V> value的类型
   * @return ConcurrentHashMap
   */
  public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap() {
    return new ConcurrentHashMap<>(DEFAULT_INITIAL_CAPACITY);
  }

  /**
   * 新建一个ConcurrentHashMap
   *
   * @param size 初始容量，当传入的容量小于等于0时，容量为{@link MapUtils#DEFAULT_INITIAL_CAPACITY}
   * @param <K> key的类型
   * @param <V> value的类型
   * @return ConcurrentHashMap
   */
  public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap(int size) {
    final int initCapacity = size <= 0 ? DEFAULT_INITIAL_CAPACITY : size;
    return new ConcurrentHashMap<>(initCapacity);
  }

  /**
   * 传入一个Map将其转化为ConcurrentHashMap类型
   *
   * @param map map
   * @param <K> key的类型
   * @param <V> value的类型
   * @return ConcurrentHashMap
   */
  public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap(Map<K, V> map) {
    if (isEmpty(map)) {
      return new ConcurrentHashMap<>(DEFAULT_INITIAL_CAPACITY);
    }
    return new ConcurrentHashMap<>(map);
  }

  /**
   * 创建Map<br>
   * 传入抽象Map{@link AbstractMap}和{@link Map}类将默认创建{@link HashMap}
   *
   * @param <K> map键类型
   * @param <V> map值类型
   * @param mapType map类型
   * @return {@link Map}实例
   */
  @SuppressWarnings("unchecked")
  public static <K, V> Map<K, V> createMap(Class<?> mapType) {
    if (mapType.isAssignableFrom(AbstractMap.class)) {
      return new HashMap<>();
    } else {
      return (Map<K, V>) ClassUtils.newInstance(mapType);
    }
  }

    /**
     * 返回一个空Map
     *
     * @param <K> 键类型
     * @param <V> 值类型
     * @return 空Map
     * @see Collections#emptyMap()
     */
    public static <K, V> Map<K, V> emptyMap() {
        return Collections.emptyMap();
    }

    /**
     * 清除一个或多个Map集合内的元素，每个Map调用clear()方法
     *
     * @param maps 一个或多个Map
     */
    public static void clear(Map<?, ?>... maps) {
        for (Map<?, ?> map : maps) {
            if (isNotEmpty(map)) {
                map.clear();
            }
        }
    }


  // ----------------------------------------------------------------------------------------------- new HashSet

  /**
   * 新建一个HashSet
   *
   * @param <T> 集合元素类型
   * @param ts  元素数组
   * @return HashSet对象
   */
  @SafeVarargs
  public static <T> HashSet<T> newHashSet(T... ts) {
    return set(false, ts);
  }

  /**
   * 新建一个LinkedHashSet
   *
   * @param <T> 集合元素类型
   * @param ts  元素数组
   * @return HashSet对象
   */
  @SafeVarargs
  public static <T> LinkedHashSet<T> newLinkedHashSet(T... ts) {
    return (LinkedHashSet<T>) set(true, ts);
  }

  /**
   * 新建一个HashSet
   *
   * @param <T>      集合元素类型
   * @param isSorted 是否有序，有序返回 {@link LinkedHashSet}，否则返回 {@link HashSet}
   * @return HashSet对象
   */
  public static <T> HashSet<T> set(boolean isSorted) {
    return set(isSorted, (T[]) null);
  }

  /**
   * 新建一个HashSet
   *
   * @param <T>      集合元素类型
   * @param isSorted 是否有序，有序返回 {@link LinkedHashSet}，否则返回 {@link HashSet}
   * @param ts       元素数组
   * @return HashSet对象
   */
  @SafeVarargs
  public static <T> HashSet<T> set(boolean isSorted, T... ts) {
    if (null == ts || ts.length==0) {
      return isSorted ? new LinkedHashSet<>() : new HashSet<>();
    }
    int initialCapacity = Math.max((int) (ts.length / .75f) + 1, 16);
    final HashSet<T> set = isSorted ? new LinkedHashSet<>(initialCapacity) : new HashSet<>(initialCapacity);
    Collections.addAll(set, ts);
    return set;
  }

  /**
   * 新建一个HashSet
   *
   * @param <T>        集合元素类型
   * @param collection 集合
   * @return HashSet对象
   */
  public static <T> HashSet<T> newHashSet(Collection<T> collection) {
    return newHashSet(false, collection);
  }

  /**
   * 新建一个HashSet
   *
   * @param <T>        集合元素类型
   * @param isSorted   是否有序，有序返回 {@link LinkedHashSet}，否则返回{@link HashSet}
   * @param collection 集合，用于初始化Set
   * @return HashSet对象
   */
  public static <T> HashSet<T> newHashSet(boolean isSorted, Collection<T> collection) {
    return isSorted ? new LinkedHashSet<>(collection) : new HashSet<>(collection);
  }

  /**
   * 新建一个HashSet
   *
   * @param <T>      集合元素类型
   * @param isSorted 是否有序，有序返回 {@link LinkedHashSet}，否则返回{@link HashSet}
   * @param iter     {@link Iterator}
   * @return HashSet对象
   */
  public static <T> HashSet<T> newHashSet(boolean isSorted, Iterator<T> iter) {
    if (null == iter) {
      return set(isSorted, (T[]) null);
    }
    final HashSet<T> set = isSorted ? new LinkedHashSet<>() : new HashSet<>();
    while (iter.hasNext()) {
      set.add(iter.next());
    }
    return set;
  }

  /**
   * 新建一个HashSet
   *
   * @param <T>         集合元素类型
   * @param isSorted    是否有序，有序返回 {@link LinkedHashSet}，否则返回{@link HashSet}
   * @param enumeration {@link Enumeration}
   * @return HashSet对象
   */
  public static <T> HashSet<T> newHashSet(boolean isSorted, Enumeration<T> enumeration) {
    if (null == enumeration) {
      return set(isSorted, (T[]) null);
    }
    final HashSet<T> set = isSorted ? new LinkedHashSet<>() : new HashSet<>();
    while (enumeration.hasMoreElements()) {
      set.add(enumeration.nextElement());
    }
    return set;
  }

  // ----------------------------------------------------------------------------------------------- List
}
